﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Serialization;

namespace WikeSoft.Core.Extension
{

    /// <summary>
    /// 字符串扩展类
    /// </summary>
    public static class StringExtension
    {
        /// <summary>
        /// 用于判断是否为空字符
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static bool IsBlank(this string s)
        {
            return s == null || (s.Trim().Length == 0);
        }

        /// <summary>
        /// 用于判断是否为非空字符
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static bool IsNotBlank(this string s)
        {
            return !s.IsBlank();
        }

        /// <summary>
        /// 判断是否为有效的Email地址
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static Boolean IsValidEmail(this string s)
        {
            if (!s.IsBlank())
            {
                return Regex.IsMatch(s,
                         @"^(?("")("".+?""@)|(([0-9a-zA-Z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-zA-Z])@))" +
                         @"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,6}))$");
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 验证是否是合法的电话号码
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static Boolean IsValidPhone(this string s)
        {
            if (!s.IsBlank())
            {
                return Regex.IsMatch(s, @"^\+?((\d{2,4}(-)?)|(\(\d{2,4}\)))*(\d{0,16})*$");
            }
            else
            {
                return true;
            }
        }
        /// <summary>
        /// 验证是否是合法的手机号码
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static Boolean IsValidMobile(this string s)
        {
            if (!s.IsBlank())
            {
                return Regex.IsMatch(s, @"^\+?\d{0,4}?[1][3-8]\d{9}$");
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 验证是否是合法的邮编
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static Boolean IsValidZipCode(this string s)
        {
            if (!s.IsBlank())
            {
                return Regex.IsMatch(s, @"[1-9]\d{5}(?!\d)");
            }
            else
            {
                return true;
            }
        }
        //2012-9-27
        /// <summary>
        /// 验证是否是合法的传真
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static Boolean IsValidFax(this string s)
        {
            if (!s.IsBlank())
            {
                return Regex.IsMatch(s, @"(^[0-9]{3,4}\-[0-9]{7,8}$)|(^[0-9]{7,8}$)|(^\([0-9]{3,4}\)[0-9]{3,8}$)|(^0{0,1}13[0-9]{9}$)");
            }
            else
            {
                return true;
            }
        }
        /// <summary>
        /// 检查字符串是否为有效的INT32数字
        /// </summary>
        /// <param name="val"></param>
        /// <returns></returns>
        public static Boolean IsInt32(this string val)
        {
            if (IsBlank(val))
                return false;
            Int32 k;
            return Int32.TryParse(val, out k);
        }

        /// <summary>
        /// 检查字符串是否为有效的INT64数字
        /// </summary>
        /// <param name="val"></param>
        /// <returns></returns>
        public static Boolean IsInt64(this string val)
        {
            if (IsBlank(val))
                return false;
            Int64 k;
            return Int64.TryParse(val, out k);
        }

        /// <summary>
        /// 检查字符串是否为有效的Decimal
        /// </summary>
        /// <param name="val"></param>
        /// <returns></returns>
        public static Boolean IsDecimal(this string val)
        {
            if (IsBlank(val))
                return false;
            decimal d;
            return Decimal.TryParse(val, out d);
        }

        /// <summary>
        /// 将字符串转换成MD5加密字符串
        /// </summary>
        /// <param name="orgStr"></param>
        /// <returns></returns>
        public static string ToMD5(this string orgStr)
        {
            MD5 md5Hasher = MD5.Create();

            // Convert the input string to a byte array and compute the hash.
            byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(orgStr));

            // Create a new Stringbuilder to collect the bytes
            // and create a string.
            StringBuilder sBuilder = new StringBuilder();

            // Loop through each byte of the hashed data 
            // and format each one as a hexadecimal string.
            for (int i = 0; i < data.Length; i++)
            {
                sBuilder.Append(data[i].ToString("x2"));
            }

            // Return the hexadecimal string.
            return sBuilder.ToString();
        }

        /// <summary>
        /// 将字符串转换成List<int>数组
        /// </summary>
        public static List<int> ToIntList(this string val, char? splitchar)
        {
            if (!splitchar.HasValue)
            {
                splitchar = ',';
            }

            val = val.IsBlank() ? string.Empty : val.Trim().Trim(splitchar.Value).Trim();

            if (val.IsBlank())
            {
                throw new ApplicationException("字符串不能为空,或者字符串没有包含除分割符以外的有效字符。");
            }

            string[] sarray = val.Split(splitchar.Value);

            List<int> list = new List<int>();

            foreach (string s in sarray)
            {
                if (s.Trim().IsInt32())
                {
                    list.Add(Convert.ToInt32(s.Trim()));
                }
            }
            return list;
        }

        /// <summary>
        /// 将字符串转换成List<int>数组(重载版本，默认使用','为分割符)
        /// </summary>
        /// <param name="val"></param>
        /// <returns></returns>
        public static List<int> ToIntList(this string val)
        {

            return ToIntList(val, default(char?));
        }




        public static string CustomToHtmlDecode(this string str)
        {
            str = str.Replace("<br/>", "\n");
            str = str.Replace("&gt", ">");
            str = str.Replace("&lt", "<");
            str = str.Replace("&nbsp;", " ");
            str = str.Replace("&quot;", "\"");
            str = str.Replace("''", "'");
            str = str.Replace("&amp", "&");

            return str;

        }

        public static string CustomToHtmlEncode(this string str)
        {

            str = str.Replace("&", "&amp");
            str = str.Replace("'", "''");
            str = str.Replace("\"", "&quot;");
            str = str.Replace(" ", "&nbsp;");
            str = str.Replace("<", "&lt;");
            str = str.Replace(">", "&gt;");
            str = str.Replace("\n", "<br/>");

            return str;

        }

        /// <summary>
        /// 将对象序列化成XML
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <returns></returns>
        public static string ToXML<T>(this T obj) where T : class
        {
            return ToXML(obj, Encoding.Default.BodyName);
        }
        public static string ToXML<T>(this T obj, string encodeName) where T : class
        {
            if (obj == null) throw new ArgumentNullException("obj", "obj is null.");

            if (obj is string) throw new ApplicationException("obj can't be string object.");

            Encoding en = Encoding.GetEncoding(encodeName);
            XmlSerializer serial = new XmlSerializer(typeof(T));
            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
            ns.Add("", "");
            MemoryStream ms = new MemoryStream();
            XmlTextWriter xt = new XmlTextWriter(ms, en);
            serial.Serialize(xt, obj, ns);
            xt.Close();
            ms.Close();
            return en.GetString(ms.ToArray());
        }
        /// <summary>
        /// 将XML字符串反序列化成对象实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="s"></param>
        /// <returns></returns>
        public static T Deserial<T>(this string s) where T : class
        {
            return Deserial<T>(s, Encoding.Default.BodyName);
        }
        public static T Deserial<T>(this string s, string encodeName) where T : class
        {
            if (s.IsBlank())
            {
                throw new ApplicationException("xml string is null or empty.");
            }
            Encoding en = Encoding.GetEncoding(encodeName);
            XmlSerializer serial = new XmlSerializer(typeof(T));
            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
            ns.Add("", "");

            return (T)serial.Deserialize(new StringReader(s));
        }
        /// <summary>
        /// 获取扩展名
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string GetExt(this string s)
        {
            string ret = string.Empty;
            if (s.Contains('.'))
            {
                string[] temp = s.Split('.');
                ret = temp[temp.Length - 1];
            }

            return ret;
        }
        /// <summary>
        /// 截断字符
        /// </summary>
        /// <param name="s"></param>
        /// <param name="len"></param>
        /// <param name="afterStr"></param>
        /// <returns></returns>
        public static string Truncate(this string s, int len, string afterStr = "...")
        {
            if (s.IsBlank())
            {
                return s;
            }
            if (s.Length <= len)
            {
                return s;
            }
            else
            {
                return string.Format("{0}{1}", s.Substring(0, len), afterStr);
            }
        }

        /// <summary>
        /// 截取html字符串长度
        /// </summary>
        /// <param name="content"></param>
        /// <param name="length"></param>
        /// <param name="afterStr"></param>
        /// <returns></returns>
        public static string TruncateHtml(this string content, int length, string afterStr = "...")
        {
            if (content.IsBlank())
                return "";
            string oldContent = content;

            Regex re = new Regex("(<(/?\\w+)((\\s+\\w+(\\s*=\\s*(?:\".*?\"|'.*?'|[^'\">\\s]+))?)+\\s*|\\s*)/?>)", RegexOptions.IgnoreCase);
            if (re.Match(content).Success)
            {
                content = re.Replace(content, "");
                //content = content.Replace("　", "").Replace(" ", "").Replace(" ", "").Replace("\n","");
                content = content.Trim().Replace("\n", "");
                if (content.Length <= length)
                {
                    if (content.Length == 0)  //全部都是HTML
                    {
                        StringBuilder sb = new StringBuilder();
                        MatchCollection cols = re.Matches(oldContent);
                        for (int i = 0; i < Math.Min(cols.Count, length); i++)
                        {
                            sb.Append(cols[i].Result("$1"));
                        }
                        return sb.ToString();
                    }
                    else
                    {
                        return oldContent;
                    }
                }
                else
                {
                    char endChar = content[length];
                    string ret = oldContent.Substring(0, GetRealIndex(oldContent, endChar, length) + 1) + afterStr;
                    MatchCollection mtcols = re.Matches(ret);
                    if (mtcols != null && mtcols.Count > 0)
                    {
                        //string mtVal = mtcols[mtcols.Count - 1].Result("$1");
                        string tag = mtcols[mtcols.Count - 1].Result("$2");
                        if (!tag.Contains('/'))
                        {
                            ret += string.Format("</{0}>", tag);
                        }

                    }

                    return ret;
                }
            }
            else
            {
                return content.Truncate(length);
            }

        }
        private static int GetRealIndex(string val, char endChar, int maxLen)
        {
            Regex re = new Regex("(</?\\w+((\\s+\\w+(\\s*=\\s*(?:\".*?\"|'.*?'|[^'\">\\s]+))?)+\\s*|\\s*)/?>)|(<[^>]+?$)", RegexOptions.IgnoreCase);

            int k = 0;

            char[] left = new char[val.Length];

            for (int i = 0; i < val.Length; i++)
            {
                left[i] = val[i];
                if (val[i] == endChar)
                {
                    string temp = new string(left);
                    temp = temp.Trim('\0');
                    temp = re.Replace(temp, "");
                    if (temp.Trim().Length >= maxLen)
                    {
                        k = i;
                        break;
                    }
                }

            }
            return k;
        }



        public static string ParserBBCODE(this string val)
        {
            if (val.IsBlank())
            {
                return val;
            }
            string[] patterns = new string[]{
                @"\[b\](.*?)\[\/b\]",
                @"\[i\](.*?)\[\/i\]",
                @"\[u\](.*?)\[\/u\]",
                @"\[size=(8\d|9\d|1\d\d|200)](.*?)\[\/size\]",
                @"\[url(?:\=?)(.*?)\](.*?)\[\/url\]",
                @"\[img(.*?)\](.*?)\[\/img\]",
                @"(?:%lb%|\s)*\[code(?:\=?)(?:.*?)\](?:%lb%|\s)*(.*?)(?:%lb%|\s)*\[\/code\](?:%lb%|\s)*",
                @"(?:%lb%|\s)*\[quote(?:\=?)(.*?)\](?:%lb%|\s)*(.*?)(?:%lb%|\s)*\[\/quote\](?:%lb%|\s)*",
                @"\[list(.*?)\](.*?)\[\*\](.*?)(?:%lb%|\s)*(\[\*\].*?\[\/list\]|\[\/list\])",
                @"(?:%lb%|\s)*\[list\](?:%lb%|\s)*(.*?)(?:%lb%|\s)*\[\/list\](?:%lb%|\s)*",
                @"(?:%lb%|\s)*\[list=(\d)\](?:%lb%|\s)*(.*?)(?:%lb%|\s)*\[\/list\](?:%lb%|\s)*",
                @"(?:%lb%){3,}",
            
            };
            string[] replace = new string[] {
                @"<b>$1</b>",
                @"<i>$1</i>",
                @"<u>$1</u>",
                "<span style=\"font-size:$1%;\">$2</span>",
                "<a href=\"$1\" target='_blank'>$2</a>",
                "<img $1 src=\"$2\" class=\"userUploadImg dy-small-img\" />",
                "<pre><code>$1</code></pre>",
                "<blockquote>$2</blockquote>",
                "[list$1]$2<li>$3</li>$4",
                "<ul>$1</ul>",
                "<ol start=$1>$2</ol>",
                "%lb%%lb%",

            };
            val = Regex.Replace(val, "<", "&lt;");
            val = Regex.Replace(val, ">", "&gt;");
            val = Regex.Replace(val, "[\r\n]", "%lb%");

            for (int i = 0; i < patterns.Length; i++)
            {
                val = Regex.Replace(val, patterns[i], replace[i]);
            }
            val = Regex.Replace(val, "%lb%", "<br />");

            val = Regex.Replace(val, @"\[:Q([^\]]+)\]", "<img src='/content/bbcode/smiley/$1.gif' style='border:none;'/>");

            return val;
        }

        /// <summary>
        /// 获取字符串长度（主要针对数据库使用）,中文和全角占两个长度
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static int GetRealLength(this string value)
        {
            try
            {
                if (value.IsBlank())
                {
                    return 0;
                }
                string str = Regex.Replace(value.Trim(), "[^-x00-xff ~!@#$%&*()_+|\\={};:\'\"/?.,<>]", "aa");
                return str.Length;
            }
            catch
            {

                return value.Length;
            }
        }
        /// <summary>
        /// 验证QQ格式
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static Boolean IsValidQQ(this string s)
        {
            if (!s.IsBlank())
            {
                return Regex.IsMatch(s, @"^[1-9]\d{4,15}$");
            }
            else
            {
                return true;
            }
        }

        /// <summary>
        /// 将指定的字符，替换成空字符
        /// </summary>
        /// <param name="value"></param>
        /// <param name="replaceWord"></param>
        /// <returns></returns>
        public static String ReplaceChar(this String value, String replaceWord)
        {
            if (value.IsBlank() || replaceWord.IsBlank())
                return value;
            RegexOptions ops = RegexOptions.Multiline;
            Regex reg = new Regex(String.Format(@"\{0}+", replaceWord), ops);
            return reg.Replace(value, replaceWord);
        }

        public static bool IsImage(this string value)
        {
            return Regex.IsMatch(value, @"\.(gif|jpg|jpeg|png|bmp|GIF|JPG|PNG|BMP)$"); 
        }

        public static bool IsValidIDCard(this string value)
        {

            if (value.Length == 18)
            {
                bool check = CheckIDCard18(value);
                return check;
            }
            else if (value.Length == 15)
            {
                bool check = CheckIDCard15(value);
                return check;
            }
            else
            {
                return false;
            }

        }


        private static bool CheckIDCard18(string Id)
        {
            long n = 0;
            if (long.TryParse(Id.Remove(17), out n) == false || n < Math.Pow(10, 16) || long.TryParse(Id.Replace('x', '0').Replace('X', '0'), out n) == false)
            {
                return false;//数字验证
            }
            string address = "11x22x35x44x53x12x23x36x45x54x13x31x37x46x61x14x32x41x50x62x15x33x42x51x63x21x34x43x52x64x65x71x81x82x91";
            if (address.IndexOf(Id.Remove(2)) == -1)
            {
                return false;//省份验证
            }
            string birth = Id.Substring(6, 8).Insert(6, "-").Insert(4, "-");
            DateTime time = new DateTime();
            if (DateTime.TryParse(birth, out time) == false)
            {
                return false;//生日验证
            }
            string[] arrVarifyCode = ("1,0,x,9,8,7,6,5,4,3,2").Split(',');
            string[] Wi = ("7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2").Split(',');
            char[] Ai = Id.Remove(17).ToCharArray();
            int sum = 0;
            for (int i = 0; i < 17; i++)
            {
                sum += int.Parse(Wi[i]) * int.Parse(Ai[i].ToString());
            }
            int y = -1;
            Math.DivRem(sum, 11, out y);
            if (arrVarifyCode[y] != Id.Substring(17, 1).ToLower())
            {
                return false;//校验码验证
            }
            return true;//符合GB11643-1999标准
        }

        private static bool CheckIDCard15(string Id)
        {
            long n = 0;
            if (long.TryParse(Id, out n) == false || n < Math.Pow(10, 14))
            {
                return false;//数字验证
            }
            string address = "11x22x35x44x53x12x23x36x45x54x13x31x37x46x61x14x32x41x50x62x15x33x42x51x63x21x34x43x52x64x65x71x81x82x91";
            if (address.IndexOf(Id.Remove(2)) == -1)
            {
                return false;//省份验证
            }
            string birth = Id.Substring(6, 6).Insert(4, "-").Insert(2, "-");
            DateTime time = new DateTime();
            if (DateTime.TryParse(birth, out time) == false)
            {
                return false;//生日验证
            }
            return true;//符合15位身份证标准

        }
    }
}
